<template>
  <div class="flex flex-col gap-y-4">
    <div v-if="create">
      <div>
        <label for="name" class="font-medium text-main">
          {{ $t("project.webhook.destination") }}
          <span class="text-red-600">*</span>
        </label>
      </div>
      <NRadioGroup class="w-full mt-1" :value="state.webhook.type">
        <div class="grid grid-cols-1 gap-4 sm:grid-cols-7">
          <template v-for="(item, index) in webhookTypeItemList" :key="index">
            <div
              class="flex justify-center px-2 py-4 rounded border border-control-border hover:bg-control-bg-hover cursor-pointer"
              @click.capture="state.webhook.type = item.type"
            >
              <div class="flex flex-col items-center">
                <WebhookTypeIcon :type="item.type" class="h-10 w-10" />
                <p class="mt-1 text-center textlabel">
                  {{ item.name }}
                </p>
                <div class="mt-3 radio text-sm">
                  <NRadio :value="item.type" />
                </div>
              </div>
            </div>
          </template>
        </div>
      </NRadioGroup>
    </div>
    <div>
      <label for="name" class="font-medium text-main">
        {{ $t("common.name") }} <span class="text-red-600">*</span>
      </label>
      <NInput
        id="name"
        v-model:value="state.webhook.title"
        name="name"
        class="mt-1 w-full"
        :placeholder="`${selectedWebhook?.name ?? 'My'} Webhook`"
        :disabled="!allowEdit"
      />
    </div>
    <div>
      <label for="url" class="font-medium text-main">
        {{ $t("project.webhook.webhook-url") }}
        <span class="text-red-600">*</span>
      </label>
      <div class="mt-1 textinfolabel">
        {{
          $t("project.webhook.creation.desc", {
            destination: selectedWebhook?.name,
          })
        }}
        <a
          :href="selectedWebhook?.docUrl"
          target="__blank"
          class="normal-link"
          >{{
            $t("project.webhook.creation.view-doc", {
              destination: selectedWebhook?.name,
            })
          }}</a
        >.
      </div>
      <NInput
        id="url"
        v-model:value="state.webhook.url"
        name="url"
        class="mt-1 w-full"
        :placeholder="selectedWebhook?.urlPlaceholder"
        :disabled="!allowEdit"
      />
    </div>
    <div>
      <div class="text-md leading-6 font-medium text-main">
        {{ $t("project.webhook.triggering-activity") }}
        <span class="text-red-600">*</span>
      </div>
      <div
        v-for="(item, index) in webhookActivityItemList"
        :key="index"
        class="mt-4 space-y-4"
      >
        <div>
          <div class="flex items-center">
            <NCheckbox
              :label="item.title"
              :checked="isEventOn(item.activity)"
              @update:checked="
                (on: boolean) => {
                  toggleEvent(item.activity, on);
                }
              "
            />
            <NTooltip
              v-if="webhookSupportDirectMessage && item.supportDirectMessage"
            >
              <template #trigger>
                <InfoIcon class="w-4 h-auto text-gray-500" />
              </template>
              {{ $t("project.webhook.activity-support-direct-message") }}
            </NTooltip>
          </div>
          <div class="textinfolabel">{{ item.label }}</div>
        </div>
      </div>
      <div class="mt-4">
        <NButton @click.prevent="testWebhook">
          {{ $t("project.webhook.test-webhook") }}
        </NButton>
      </div>
    </div>
    <div v-if="webhookSupportDirectMessage && activitySupportDirectMessage">
      <div class="text-md leading-6 font-medium text-main">
        {{ $t("project.webhook.direct-messages") }}
      </div>
      <span class="mt-1 textinfolabel">
        {{ $t("project.webhook.direct-messages-tip") }}
      </span>
      <BBAttention v-if="!imApp?.enabled" class="mt-2 mb-4" type="warning">
        <template #default>
          <i18n-t
            class="textinfolabel"
            tag="div"
            keypath="project.webhook.direct-messages-warning"
          >
            <template #im>
              <router-link
                target="_blank"
                class="normal-link"
                :to="{ name: WORKSPACE_ROUTE_IM }"
              >
                {{ $t("settings.sidebar.im-integration") }}
              </router-link>
            </template>
          </i18n-t>
        </template>
      </BBAttention>
      <div class="flex items-center mt-2">
        <NCheckbox
          v-model:checked="state.webhook.directMessage"
          :label="$t('project.webhook.enable-direct-messages')"
        />
      </div>
    </div>
    <div
      class="flex mt-2 pt-4 border-t"
      :class="!create && allowEdit ? 'justify-between' : 'justify-end'"
    >
      <BBButtonConfirm
        v-if="!create && allowEdit"
        :style="'DELETE'"
        :button-text="$t('project.webhook.deletion.btn-text')"
        :ok-text="$t('common.delete')"
        :confirm-title="
          $t('project.webhook.deletion.confirm-title', { title: webhook.title })
        "
        :confirm-description="$t('common.cannot-undo-this-action')"
        :require-confirm="true"
        @confirm="deleteWebhook"
      />
      <div class="space-x-3">
        <NButton v-if="create" @click.prevent="cancel">
          {{ $t("common.cancel") }}
        </NButton>
        <NButton v-else-if="valueChanged" @click.prevent="discardChanges">
          {{ $t("common.discard-changes") }}
        </NButton>
        <template v-if="allowEdit">
          <NButton
            v-if="create"
            type="primary"
            :disabled="!allowCreate"
            @click.prevent="createWebhook"
          >
            {{ $t("common.create") }}
          </NButton>
          <NButton
            v-else
            type="primary"
            :disabled="
              !valueChanged || state.webhook.notificationTypes.length === 0
            "
            @click.prevent="updateWebhook"
          >
            {{ $t("common.update") }}
          </NButton>
        </template>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { cloneDeep, isEmpty, isEqual } from "lodash-es";
import { InfoIcon } from "lucide-vue-next";
import {
  NButton,
  NCheckbox,
  NInput,
  NRadio,
  NRadioGroup,
  NTooltip,
} from "naive-ui";
import { reactive, computed, watch } from "vue";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import { BBAttention, BBButtonConfirm } from "@/bbkit";
import {
  PROJECT_V1_ROUTE_WEBHOOKS,
  PROJECT_V1_ROUTE_WEBHOOK_DETAIL,
} from "@/router/dashboard/projectV1";
import { WORKSPACE_ROUTE_IM } from "@/router/dashboard/workspaceRoutes";
import {
  pushNotification,
  useProjectV1Store,
  useProjectWebhookV1Store,
  useGracefulRequest,
  useSettingV1Store,
} from "@/store";
import {
  type ComposedProject,
  projectWebhookV1ActivityItemList,
  projectWebhookV1TypeItemList,
} from "@/types";
import {
  Webhook_Type,
  type Activity_Type,
  type Webhook,
} from "@/types/proto/v1/project_service";
import { projectWebhookV1Slug } from "../utils";
import WebhookTypeIcon from "./Project/WebhookTypeIcon.vue";

interface LocalState {
  webhook: Webhook;
}

const props = withDefaults(
  defineProps<{
    allowEdit?: boolean;
    create: boolean;
    project: ComposedProject;
    webhook: Webhook;
  }>(),
  {
    allowEdit: true,
  }
);

const router = useRouter();
const { t } = useI18n();

const settingStore = useSettingV1Store();
const projectStore = useProjectV1Store();
const projectWebhookV1Store = useProjectWebhookV1Store();

const state = reactive<LocalState>({
  webhook: cloneDeep(props.webhook),
});

watch(
  () => props.webhook,
  (webhook) => {
    state.webhook = cloneDeep(webhook);
  }
);

const valueChanged = computed(() => {
  return !isEqual(props.webhook, state.webhook);
});

const allowCreate = computed(() => {
  return (
    !isEmpty(state.webhook.title) &&
    !isEmpty(state.webhook.url) &&
    !isEmpty(state.webhook.notificationTypes)
  );
});

const discardChanges = () => {
  state.webhook = cloneDeep(props.webhook);
};

const isEventOn = (type: Activity_Type) => {
  return state.webhook.notificationTypes.includes(type);
};

const webhookActivityItemList = computed(() =>
  projectWebhookV1ActivityItemList()
);

const webhookTypeItemList = computed(() => projectWebhookV1TypeItemList());

const selectedWebhook = computed(() => {
  return webhookTypeItemList.value.find(
    (item) => item.type === state.webhook.type
  );
});

const imSetting = computed(
  () => settingStore.getSettingByName("bb.app.im")?.value?.appImSettingValue
);

const imApp = computed(() => {
  if (!selectedWebhook.value?.supportDirectMessage) {
    return undefined;
  }
  switch (selectedWebhook.value.type) {
    case Webhook_Type.TYPE_SLACK:
      return imSetting.value?.slack;
    case Webhook_Type.TYPE_FEISHU:
      return imSetting.value?.feishu;
    case Webhook_Type.TYPE_WECOM:
      return imSetting.value?.wecom;
  }
  return undefined;
});

const webhookSupportDirectMessage = computed(
  () => selectedWebhook.value?.supportDirectMessage
);

const activitySupportDirectMessage = computed(() => {
  return state.webhook.notificationTypes.some(
    (event) =>
      webhookActivityItemList.value.find((item) => item.activity === event)
        ?.supportDirectMessage
  );
});

const toggleEvent = (type: Activity_Type, on: boolean) => {
  if (on) {
    if (state.webhook.notificationTypes.includes(type)) {
      return;
    }
    state.webhook.notificationTypes.push(type);
  } else {
    const index = state.webhook.notificationTypes.indexOf(type);
    if (index >= 0) {
      state.webhook.notificationTypes.splice(index, 1);
    }
  }
  state.webhook.notificationTypes.sort();
};

const cancel = () => {
  router.push({
    name: PROJECT_V1_ROUTE_WEBHOOKS,
  });
};

const createWebhook = () => {
  useGracefulRequest(async () => {
    const { webhook } = state;
    const updatedProject = await projectWebhookV1Store.createProjectWebhook(
      props.project.name,
      webhook
    );
    projectStore.updateProjectCache({
      ...props.project,
      ...updatedProject,
    });

    pushNotification({
      module: "bytebase",
      style: "SUCCESS",
      title: t("project.webhook.success-created-prompt", {
        name: webhook.title,
      }),
    });
    const createdWebhook = updatedProject.webhooks.find((wh) => {
      return (
        wh.title === webhook.title &&
        wh.type == webhook.type &&
        wh.url === webhook.url
      );
    });
    if (createdWebhook) {
      router.push({
        name: PROJECT_V1_ROUTE_WEBHOOK_DETAIL,
        params: {
          projectWebhookSlug: projectWebhookV1Slug(createdWebhook),
        },
      });
    }
  });
};

const updateWebhook = () => {
  useGracefulRequest(async () => {
    const updateMask: string[] = [];
    if (state.webhook.title !== props.webhook.title) {
      updateMask.push("title");
    }
    if (state.webhook.url !== props.webhook.url) {
      updateMask.push("url");
    }
    if (state.webhook.directMessage !== props.webhook.directMessage) {
      updateMask.push("direct_message");
    }
    if (
      !isEqual(state.webhook.notificationTypes, props.webhook.notificationTypes)
    ) {
      updateMask.push("notification_type");
    }
    const updatedProject = await projectWebhookV1Store.updateProjectWebhook(
      state.webhook,
      updateMask
    );
    projectStore.updateProjectCache({
      ...props.project,
      ...updatedProject,
    });
    pushNotification({
      module: "bytebase",
      style: "SUCCESS",
      title: t("project.webhook.success-updated-prompt", {
        name: state.webhook.title,
      }),
    });
  });
};

const deleteWebhook = () => {
  useGracefulRequest(async () => {
    const name = state.webhook.title;
    const updatedProject = await projectWebhookV1Store.deleteProjectWebhook(
      state.webhook
    );
    projectStore.updateProjectCache({
      ...props.project,
      ...updatedProject,
    });
    pushNotification({
      module: "bytebase",
      style: "SUCCESS",
      title: t("project.webhook.success-deleted-prompt", {
        name,
      }),
    });
    cancel();
  });
};

const testWebhook = () => {
  useGracefulRequest(async () => {
    const result = await useProjectWebhookV1Store().testProjectWebhook(
      props.project,
      state.webhook
    );

    if (result.error) {
      pushNotification({
        module: "bytebase",
        style: "CRITICAL",
        title: t("project.webhook.fail-tested-title"),
        description: result.error,
        manualHide: true,
      });
    } else {
      pushNotification({
        module: "bytebase",
        style: "SUCCESS",
        title: t("project.webhook.success-tested-prompt"),
      });
    }
  });
};
</script>
